package com.rbac.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rbac.common.RedisKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

@Service
public class RedisService {
	@Value("${app.env:dev}")
	private String env;
	
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	
	@Autowired
	private ObjectMapper objectMapper;
	
	public String buildKey(RedisKey key, Object... args) {
		return key.build(env, args);
	}
	
	public void setString(RedisKey key, String value, Duration overrideTtl, Object... args) {
		String k = buildKey(key, args);
		if (overrideTtl != null && !overrideTtl.isZero() && !overrideTtl.isNegative()) {
			stringRedisTemplate.opsForValue().set(k, value, overrideTtl.getSeconds(), TimeUnit.SECONDS);
		} else if (!key.ttl().isZero()) {
			stringRedisTemplate.opsForValue().set(k, value, key.ttl().getSeconds(), TimeUnit.SECONDS);
		} else {
			stringRedisTemplate.opsForValue().set(k, value);
		}
	}
	
	public String getString(RedisKey key, Object... args) {
		return stringRedisTemplate.opsForValue().get(buildKey(key, args));
	}
	
	public void delete(RedisKey key, Object... args) {
		stringRedisTemplate.delete(buildKey(key, args));
	}
	
	public void setJson(RedisKey key, Object value, Duration overrideTtl, Object... args) {
		try {
			String json = objectMapper.writeValueAsString(value);
			setString(key, json, overrideTtl, args);
		} catch (Exception e) {
			throw new RuntimeException("Failed to serialize JSON for key: " + key, e);
		}
	}
	
	public <T> T getJson(RedisKey key, Class<T> clazz, Object... args) {
		try {
			String json = getString(key, args);
			if (json == null) return null;
			return objectMapper.readValue(json, clazz);
		} catch (Exception e) {
			throw new RuntimeException("Failed to deserialize JSON for key: " + key, e);
		}
	}
	
	public <T> T getJson(RedisKey key, TypeReference<T> typeRef, Object... args) {
		try {
			String json = getString(key, args);
			if (json == null) return null;
			return objectMapper.readValue(json, typeRef);
		} catch (Exception e) {
			throw new RuntimeException("Failed to deserialize JSON for key: " + key, e);
		}
	}
} 